package com.pdg.mcplugin.tsa.old;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;

import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;

import com.pdg.mcplugin.common.deprecated.BlockProtector;

public class DataProvider {
	//plugin
	private TSA plugin;
	public TSA getPlugin(){
		return plugin;
	}
	
	//logger
	public Logger getLogger(){
		return getPlugin().getLogger();
	}
	
	private BlockProtector blockProtector=null;
	private BlockProtector getBlockProtector(){
		if(blockProtector==null){
			blockProtector = new BlockProtector(getConnection(),getLogger(),Constants.pluginName,Constants.tablePrefix);
		}
		return blockProtector;
	}
	
	private void ensureDataFolder(){
		File folder = getPlugin().getDataFolder();
		if(!folder.exists()){
			if(folder.mkdir()){
				getLogger().info(Constants.messageCreatedDataFolder);
			}else{
				getLogger().severe(Constants.errorCouldNotCreateDataFolder);
			}
		}
	}
	
	//connection
	private Connection connection;
	public Connection getConnection(){
		if(connection==null){
			ensureDataFolder();
			try{
				Class.forName(Constants.classNameSQLite);
			} catch(Exception e){
				getLogger().info(Constants.errorCouldNotLoadSQLite);
				e.printStackTrace();
				return null;
			}
			try{
				connection = DriverManager.getConnection(String.format(Constants.connectionString,getPlugin().getDataFolder().toString()));
			}catch(Exception e){
				getLogger().info(Constants.errorCouldNotConnectToDatabase);
				e.printStackTrace();
				connection = null;
				return null;
			}
		}
		return connection;
	}
	
	private void ensureArrivalsTable(){
		try{
			Statement statement = getConnection().createStatement();
			ResultSet result = statement.executeQuery(Constants.dbCheckForArrivalsTable);
			if(!result.next()){
				statement = getConnection().createStatement();
				statement.execute(Constants.dbCreateArrivalsTable);
			}
		}catch(Exception e){
			getLogger().info(Constants.errorCouldNotCreateArrivalsTable);
			e.printStackTrace();
		}
	}
	
	private void ensureContrabandTable(){
		try{
			Statement statement = getConnection().createStatement();
			ResultSet result = statement.executeQuery(Constants.dbCheckForContrabandTable);
			if(!result.next()){
				statement = getConnection().createStatement();
				statement.execute(Constants.dbCreateContrabandTable);
				
				for(Material material:Constants.defaultContraband){
					prohibitContraband(material);
				}
			}
		}catch(Exception e){
			getLogger().info(Constants.errorCouldNotCreateContrabandTable);
			e.printStackTrace();
		}
	}
	
	private String sqlSafeName(String theName){
		return theName.replaceAll("'","''");
	}
	
	//create an arrival point
	public boolean createArrival(String arrivalName,Location arrivalLocation){
		ensureArrivalsTable();
		if(retrieveArrival(arrivalName)!=null) return false;
		try{
			Statement statement = getConnection().createStatement();
			statement.execute(String.format(Constants.dbInsertArrivalPoint,sqlSafeName(arrivalName), sqlSafeName(arrivalLocation.getWorld().getName()),arrivalLocation.getX(),arrivalLocation.getY(),arrivalLocation.getZ()));
			return true;
		}catch(Exception e){
			getLogger().severe(Constants.errorCouldNotCreateArrivalPoint);
			e.printStackTrace();
		}
		return false;
	}
	
	//retrieve an arrival point
	public Location retrieveArrival(String arrivalName){
		ensureArrivalsTable();
		try{
			Statement statement = getConnection().createStatement();
			ResultSet result = statement.executeQuery(String.format(Constants.dbRetrieveArrivalPoint,sqlSafeName(arrivalName)));
			if(result.next()){
				return new Location(
						getPlugin().getServer().getWorld(result.getString(Constants.fieldArrivalWorld)),
						result.getDouble(Constants.fieldArrivalX),
						result.getDouble(Constants.fieldArrivalY),
						result.getDouble(Constants.fieldArrivalZ));
			}
		}catch(Exception e){
			getLogger().severe(Constants.errorCouldNotRetrieveArrivalPoint);
			e.printStackTrace();
			return null;
		}
		return null;
	}
	
	//delete an arrival point
	public boolean deleteArrival(String arrivalName){
		ensureArrivalsTable();
		if(retrieveArrival(arrivalName)==null) return false;
		try{
			Statement statement = getConnection().createStatement();
			statement.execute(String.format(Constants.dbDeleteArrivalPoint,arrivalName));
			return true;
		}catch(Exception e){
			getLogger().severe(Constants.errorCouldNotDeleteArrivalPoint);
			e.printStackTrace();
			return false;
		}
	}
	
	public boolean permitContraband(Material theMaterial){
		ensureContrabandTable();
		if(!checkContraband(theMaterial)){
			return true;
		}else{
			try{
				Statement statement = getConnection().createStatement();
				statement.execute(String.format(Constants.dbPermitContraband,theMaterial.getId()));
				return true;
			}catch(Exception e){
				getLogger().severe(Constants.errorCouldNotPermitContraband);
				e.printStackTrace();
				return false;
			}
		}
	}
	
	public boolean prohibitContraband(Material theMaterial){
		ensureContrabandTable();
		if(checkContraband(theMaterial)){
			return true;
		}else{
			try{
				Statement statement = getConnection().createStatement();
				statement.execute(String.format(Constants.dbProhibitContraband,theMaterial.getId()));
				return true;
			}catch(Exception e){
				getLogger().severe(Constants.errorCouldNotProhibitContraband);
				e.printStackTrace();
				return false;
			}
		}
	}
	
	public boolean checkContraband(Material theMaterial){
		ensureContrabandTable();
		try{
			Statement statement=getConnection().createStatement();
			ResultSet result = statement.executeQuery(String.format(Constants.dbCheckContraband, theMaterial.getId()));
			if(result.next()){
				return true;
			}else{
				return false;
			}
		}catch(Exception e){
			e.printStackTrace();
			return false;
		}
	}
	
	public void clearContraband(){
		ensureContrabandTable();
		try{
		Statement statement = getConnection().createStatement();
		statement.execute(Constants.dbClearContraband);
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
	public HashSet<Material> listContraband(){
		ensureContrabandTable();
		try{
			Statement statement = getConnection().createStatement();
			ResultSet result = statement.executeQuery(String.format(Constants.dbListContraband));
			HashSet<Material> materials = new HashSet<Material>();
			while(result.next()){
				Material material = Material.getMaterial(result.getInt(Constants.fieldMaterialId));
				materials.add(material);
			}
			return materials;
		}catch(Exception e){
			e.printStackTrace();
			return null;
		}
	}
	
	public boolean setBlockProtection(Location theLocation,Integer theProtectionLevel){
		return getBlockProtector().setBlockProtection(theLocation,theProtectionLevel);
	}
	
	public Integer getBlockProtection(Location theLocation){
		return getBlockProtector().getBlockProtection(theLocation);
	}
	
	public boolean incrementBlockProtection(Location theLocation){
		return setBlockProtection(theLocation,getBlockProtection(theLocation)+1);
	}
	
	public boolean decrementBlockProtection(Location theLocation){
		return setBlockProtection(theLocation,getBlockProtection(theLocation)-1);
	}
	
	//constructor
	public DataProvider(TSA thePlugin){
		plugin = thePlugin;
	}

	public void exportContraband(CommandSender theCommandSender) {
		HashSet<Material> contraband = listContraband();
		List<String> export = new ArrayList<String>();
		Iterator<Material> iterator = contraband.iterator();
		while(iterator.hasNext()){
			Material theMaterial = iterator.next();
			export.add(theMaterial.toString());
		}
		String theFileName = String.format(Constants.exportImportFileName, getPlugin().getDataFolder().getName());
		YamlConfiguration config = new YamlConfiguration();
		config.set(Constants.contrabandList, export);
		try {
			config.save(theFileName);
			theCommandSender.sendMessage(Constants.messageExportedContraband);
		} catch (IOException e) {
			e.printStackTrace();
			theCommandSender.sendMessage(Constants.errorDidNotExportContraband);
		}
	}

	public void importContraband(CommandSender theCommandSender) {
		String theFileName = String.format(Constants.exportImportFileName, getPlugin().getDataFolder().getName());
		YamlConfiguration config = new YamlConfiguration();
		try {
			config.load(theFileName);
			List<String> theImport = config.getStringList(Constants.contrabandList);
			clearContraband();
			Iterator<String> iterator = theImport.iterator();
			while(iterator.hasNext()){
				String theMaterialName = iterator.next();
				Material theMaterial = Material.valueOf(theMaterialName);
				prohibitContraband(theMaterial);
			}
			theCommandSender.sendMessage(Constants.messageImportedContraband);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			theCommandSender.sendMessage(Constants.errorDidNotImportContraband);
		} catch (IOException e) {
			e.printStackTrace();
			theCommandSender.sendMessage(Constants.errorDidNotImportContraband);
		} catch (InvalidConfigurationException e) {
			e.printStackTrace();
			theCommandSender.sendMessage(Constants.errorDidNotImportContraband);
		}
		
	}
}
